﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Etapa1.SofRender
{
    /// <summary>
    /// NAO LEVA EM CONTA A PROFUNDIDADE DOS TRIANGULOS (FORWARD DIFERRENCING)
    /// DA PROBLEMA COM PROJECAO PERSPECTIVA
    /// </summary>
    public class Rasterizer
    {        
        public Rasterizer()
        {
            
        }
        List<VertexType> vos = new List<VertexType>();

        public List<VertexType> DrawTriangle(Triangle t1)
        {
            vos.Clear();
             Edge[] edges = new Edge[]{
                new Edge(t1.P1,t1.P2) , new Edge(t1.P2,t1.P3), new Edge(t1.P3,t1.P1)};

             int maxLength = 0;
             int longEdge = 0;

             // find edge with the greatest length in the y axis
             for (int i = 0; i < 3; i++)
             {
                 int length = (int)edges[i].P2.Y - (int)edges[i].P1.Y;
                 if (length > maxLength)
                 {
                     maxLength = length;
                     longEdge = i;
                 }
             }

             int shortEdge1 = (longEdge + 1) % 3;
             int shortEdge2 = (longEdge + 2) % 3;

             // draw spans between edges; the long edge can be drawn
             // with the shorter edges to draw the full triangle
             DrawSpansBetweenEdges(edges[longEdge], edges[shortEdge1]);
             DrawSpansBetweenEdges(edges[longEdge], edges[shortEdge2]);
             return vos;
        
        }

        private void DrawSpansBetweenEdges(Edge e1, Edge e2)
        {
            // calculate difference between the y coordinates
            // of the first edge and return if 0
            float e1ydiff = (float)(e1.P2.Y - e1.P1.Y);
            if (e1ydiff == 0.0f)
                return;

            // calculate difference between the y coordinates
            // of the second edge and return if 0
            float e2ydiff = (float)(e2.P2.Y - e2.P1.Y);
            if (e2ydiff == 0.0f)
                return;

            // calculate differences between the x coordinates
            // and colors of the points of the edges
        float e1xdiff = (float)(e1.P2.X - e1.P1.X);
        float e2xdiff = (float)(e2.P2.X - e2.P1.X);

        Dictionary<Slots, Vector4> Data1 = new Dictionary<Slots, Vector4>();
        Dictionary<Slots, Vector4> Data2 = new Dictionary<Slots, Vector4>();
        foreach (var item in e1.VertexType2.VertexElements)
        {
            Vector4 e1colordiff  = e1.VertexType2[item] - e1.VertexType1[item];
            Vector4 e2colordiff = e2.VertexType2[item] - e2.VertexType1[item];
            Data1[item] = e1colordiff;
            Data2[item] = e2colordiff;
        }
        

         

        // calculate factors to use for interpolation
        // with the edges and the step values to increase
        // them by after drawing each span
        float factor1 = (float)(e2.P1.Y - e1.P1.Y) / e1ydiff;
        float factorStep1 = 1.0f / e1ydiff;
        float factor2 = 0.0f;
        float factorStep2 = 1.0f / e2ydiff;

            // loop through the lines between the edges and draw spans
            for(int y = (int) e2.P1.Y; y < (int)e2.P2.Y; y++) {
                // create and draw span    

                Dictionary<Slots, Vector4> Datax1 = new Dictionary<Slots, Vector4>();
                Dictionary<Slots, Vector4> Datax2 = new Dictionary<Slots, Vector4>();
                foreach (var item in e1.VertexType2.VertexElements)
                {
                    Vector4 x1 =  e1.VertexType1[item] + Data1[item] * factor1;
                    Vector4 x2 =  e2.VertexType1[item] + Data2[item] * factor2;
                    Datax1[item] = x1;
                    Datax2[item] = x2;
                }

                Span span = new Span(Datax1,
                          (int)e1.P1.X + (int)(e1xdiff * factor1),
                          Datax2,
                          (int)e2.P1.X + (int)(e2xdiff * factor2));

                DrawSpan(span, y);

                // increase factors
                factor1 += factorStep1;
                factor2 += factorStep2;
        }




        }

        private void DrawSpan(Span span, int y)
        {
            int xdiff = span.X2 - span.X1;
            if (xdiff == 0)
                return;

            Dictionary<Slots, Vector4> Data = new Dictionary<Slots, Vector4>();
            foreach (var item in span.d1.Keys)
            {
                Data[item] = span.d2[item] - span.d1[item];
                //Color colordiff = span.Color2.SubColors(span.Color1);
            }         
            

            float factor = 0.0f;
            float factorStep = 1.0f / (float)xdiff;

            // draw each pixel in the span
            for (int x = span.X1; x < span.X2; x++)
            {
                VertexType vo = new VertexType();
                foreach (var item in Data.Keys)
                {
                           
                           vo[item] = span.d1[item] + Data[item] * factor;                            
                           //span.Color1.AddColors(colordiff.MultByConstColor(factor))
                }

                vo[Slots.POSITION0] = new Vector4(x, y, vo[Slots.POSITION0].Z, 0);
                vos.Add(vo);
                //render.SetPixel(x, y, 10 ,span.Color1.AddColors(colordiff.MultByConstColor(factor)));
                factor += factorStep;
            }
        }       
        

    }
}
